package manager;

import io.ClassRoomReader;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import entities.ClassRoom;
import entities.Course;
import entities.TimeTableColumn;
import entities.TimeTableRow;

public class Manager {
	protected ArrayList<ClassRoom> ClassRoomEntries;
	protected TimeTableColumn correct_t;
	protected TimeTableRow correct_w;

	private class ClassRoomComparator implements Comparator<ClassRoom> {
		@Override
		public int compare(ClassRoom obj1, ClassRoom obj2) {
			return Integer.compare(obj1.get_capacity(), obj2.get_capacity());
		}

	}

	private class CourseComparator implements Comparator<Course> {
		@Override
		public int compare(Course obj1, Course obj2) {
			return Integer.compare(obj1.get_capacity(), obj2.get_capacity());
		}

	}

	private boolean checkequal(int n1, int n2) {
		return (n1 == n2);
	}

	public Manager() throws FileNotFoundException, IOException {

		this.ClassRoomEntries = (new ClassRoomReader()).getEntries();

		Collections.sort(this.ClassRoomEntries, new ClassRoomComparator());
		Collections.reverse(this.ClassRoomEntries);
	}

	// Calculate the future usage of the classroom
	public boolean calculatePrecentage(Course courseTable) {

		int occupied = courseTable.get_capacity();

		for (ClassRoom res : ClassRoomEntries) {
			int classRoomCapacity = res.get_capacity();

			double percentage = (occupied / (classRoomCapacity * 1.0)) * 100;

			// Check if the future usage of the classroom fulfill the
			// requirement of 60%
			if (percentage >= 60.0 && percentage <= 100.0) {
				if (checknull(res, courseTable)) {
					courseTable.set_assigned_crm(res.get_roomNumber());
					return true;
				}
			}

		}

		return false;
	}

	// Check the availability of the classroom
	public boolean checknull(ClassRoom res, Course courseTable) {

		for (TimeTableRow row : res.get_timetable()) {
			// Calculate the current week checking
			int w = courseTable.get_index_w();
			courseTable.set_index_w(++w);

			for (TimeTableColumn column : row) {
				// Calculate the current day checking
				int t = courseTable.get_index_t();
				courseTable.set_index_t(++t);

				boolean satisfy = true;
				int i = 0;

				// Check the first column that is available
				if (column.isAvailable()) {
					boolean found = false;

					for (TimeTableColumn temp : row) {

						// Get the current checking column and check the next
						// time slot availability
						if (temp == column)
							found = true;

						if (i < courseTable.get_duration() && satisfy && found) {
							if (temp.isAvailable()) {
								satisfy = true;
								i++;
							}

							else {
								satisfy = false;
								break;
							}
						}

					}

					// The number of available time slot cannot meet the
					// requirement
					// For checking the end of the day
					if (!checkequal(i, courseTable.get_duration()))
						satisfy = false;
				}

				else {
					satisfy = false;
				}

				if (satisfy && checkLecturer(res, courseTable)) {

					// Get the correct date and week for future checking
					correct_t = column;
					correct_w = row;
					return true;
				}

			}
			// Roll back to start of the next day
			courseTable.set_index_t(0);
		}
		courseTable.set_index_w(0);
		return false;
	}

	// Check the availability of the lecturer fulfill the requirement or not
	public boolean checkLecturer(ClassRoom res, Course courseTable) {
		String lect = courseTable.get_instructor();

		for (ClassRoom rm : ClassRoomEntries) {
			// Check the classroom that is not equal to the assigned classroom
			if (rm != res) {
				int i = 1;
				int j = 1;

				for (TimeTableRow row : rm.get_timetable()) {

					// Get the same week for the courses of other classroom
					if (checkequal(i, courseTable.get_index_w())) {

						for (TimeTableColumn column : row) {
							// Get the same time slot for the courses of other
							// classroom
							if (checkequal(j, courseTable.get_index_t())) {

								if (!column.isAvailable()) {
									// Check if the lecturer will occur in
									// different classroom at the same time slot
									// or not
									if (column.getInstructor().equals(lect)) {
										return false;
									}
								}

							}
							j++;
						}
						i++;
					}
				}

			}
		}
		return true;
	}

	// public void swtichClass(){}

	// Write to the classroom timetable finally
	public void write(Course _time_table_entry) {

		boolean found = false;

		for (ClassRoom res : ClassRoomEntries) {
			// Find the assigned room number
			if (res.get_roomNumber() == _time_table_entry.get_assigned_crm()) {

				int j = 0;

				for (TimeTableColumn t : correct_w) {

					// Find the assigned time slot
					if (t == correct_t) {
						found = true;
					}

					if (j < _time_table_entry.get_duration() && found) {
						t.setClass(_time_table_entry);
						j++;

					}
				}

				return;

			}
		}
	}

	// Print the time table of the classroom
	public void printTable() {

		for (ClassRoom res : ClassRoomEntries) {
			for (TimeTableRow row : res.get_timetable()) {
				for (TimeTableColumn column : row) {
					if (!column.isAvailable()) {
						int n = column.getCount();
						column.setCount(++n);
					}

					if (!column.isAvailable()
							&& checkequal(column.getCount(),
									column.getDuration())) {
						System.out.println(column);
						System.out.println();
					}
				}
			}
		}
	}

	public void validate(ArrayList<Course> courseTable) {

		Collections.sort(courseTable, new CourseComparator());
		Collections.reverse(courseTable);

		for (Course row : courseTable) {
			if (calculatePrecentage(row)) {
				write(row);
			} else {
				// swtichClass();
				System.out.println(row.get_ID() + " cannot find the classroom\n");
			}
		}
		printTable();
	}
}
